﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="LanguageContainer.cs" company="">
//   
// </copyright>
// <summary>
//   The language container.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Localization
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Resources;

    /// <summary>
    /// The language container.
    /// </summary>
    public class LanguageContainer : ILanguageContainer
    {
        public static LanguageContainer Instance
        {
            get
            {
                return _instance ?? (_instance = new LanguageContainer());
            }
        }

        private static LanguageContainer _instance;

        #region Constants and Fields

        /// <summary>
        /// The _dictionery.
        /// </summary>
        internal Dictionary<string, string> _dictionery;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="LanguageContainer"/> class.
        /// </summary>
        protected LanguageContainer()
        {
            this.Init();
            this.Refresh();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="LanguageContainer"/> class.
        /// </summary>
        /// <param name="filePath">
        /// The file path.
        /// </param>
        public LanguageContainer(string filePath)
        {
            this.Init();
            this.Refresh(filePath);
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the current culture info.
        /// </summary>
        /// <value>The current culture info.</value>
        public CultureInfo CurrentCultureInfo { get; set; }

        #endregion

        #region Public Indexers

        /// <summary>
        /// Sets the option to use the container as Dictionary.
        /// </summary>
        /// <value></value>
        /// <param name="term">the term to solve from dictionary</param>
        /// <returns>the resolved term.</returns>
        public string this[string term]
        {
            get
            {
                if (this._dictionery.ContainsKey(term))
                {
                    return this._dictionery[term];
                }

                Trace.WriteLine(string.Format("{0} is not defined in {1} culture", term, this.CurrentCultureInfo.Name));
                return "Not Defined";
            }
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// Changes the culture.
        /// </summary>
        /// <param name="cultureName">
        /// Name of the culture.
        /// </param>
        public void ChangeCulture(string cultureName)
        {
            this.CurrentCultureInfo = new CultureInfo(cultureName);
            this.Refresh();
        }

        /// <summary>
        /// Return the available cultures.
        /// </summary>
        /// <returns>
        /// List of available cultures.
        /// </returns>
        public List<string> CulturesAvilable()
        {
            DirectoryInfo langDirectory = GetLangDirectory();
            return langDirectory.GetFiles("*.resx").Select(file => file.Name.Split('.').First()).ToList();
        }

        /// <summary>
        /// Gets the current culture.
        /// </summary>
        /// <returns>
        /// The current culture.
        /// </returns>
        public string CurrentCulture()
        {
            return this.CurrentCultureInfo.Name;
        }

        #endregion

        #region Methods

        /// <summary>
        /// The get lang directory.
        /// </summary>
        /// <returns>
        /// Dictionary contains directory.
        /// </returns>
        [ExcludeFromCodeCoverage]
        internal static DirectoryInfo GetLangDirectory()
        {
            return new DirectoryInfo(Environment.CurrentDirectory);
        }

        /// <summary>
        /// The fill language dictionary.
        /// </summary>
        /// <param name="langFilePath">
        /// The lang file path.
        /// </param>
        internal void FillLanguageDictionary(string langFilePath)
        {
            var resXResourceReader = new ResXResourceReader(langFilePath);
            try
            {
                foreach (DictionaryEntry entery in resXResourceReader)
                {
                    this._dictionery.Add(entery.Key.ToString(), entery.Value.ToString());
                }
            }
            catch (DirectoryNotFoundException e)
            {
                Trace.WriteLine(e);
            }
        }

        /// <summary>
        /// The initialize method.
        /// </summary>
        internal void Init()
        {
            this.CurrentCultureInfo = new CultureInfo("en-US");
        }

        /// <summary>
        /// The refresh.
        /// </summary>
        internal void Refresh()
        {
            this._dictionery = new Dictionary<string, string>();
            string langFilePath = GetLangDirectory().FullName;
            langFilePath += "\\" + this.CurrentCultureInfo.Name + ".resx";
            this.FillLanguageDictionary(langFilePath);
            this.FillDictionaryWithFallbackValues();
        }

        /// <summary>
        /// The refresh.
        /// </summary>
        /// <param name="filePath">
        /// The file path.
        /// </param>
        internal void Refresh(string filePath)
        {
            this._dictionery = new Dictionary<string, string>();
            this.FillLanguageDictionary(filePath);
        }

        /// <summary>
        /// The fill dictionary with fallback values.
        /// </summary>
        private void FillDictionaryWithFallbackValues()
        {
            string filePath = this.GetFallbackFilePath();
            var resXResourceReader = new ResXResourceReader(filePath);
            try
            {
                foreach (DictionaryEntry entery in resXResourceReader)
                {
                    if (!this._dictionery.ContainsKey(entery.Key.ToString()))
                    {
                        this._dictionery.Add(entery.Key.ToString(), entery.Value.ToString());
                    }
                }
            }
            catch (DirectoryNotFoundException e)
            {
                Trace.WriteLine(e);
            }
        }

        /// <summary>
        /// The get fallback file path.
        /// </summary>
        /// <returns>
        /// The get fallback file path.
        /// </returns>
        private string GetFallbackFilePath()
        {
            string langFilePath = GetLangDirectory().FullName;
            langFilePath += "\\" + "en-US" + ".resx";
            return langFilePath;
        }

        #endregion
    }
}